/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ipark.gui.mapeditor;

import java.awt.*;
import java.awt.event.*;
import java.io.Serializable;
import java.util.*;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
/**
 * class, which represents floor
 * @author jernej
 */
public class WorkArea extends JPanel implements Serializable{
    
  private final int RESIZE_HORIZONTAL_RIGHT       = 1;
  private final int RESIZE_VERTICAL_BOTTOM        = 2;
  private final int RESIZE_HORIZONTAL_LEFT        = 3;
  private final int RESIZE_VERTICAL_TOP           = 4;
  private final int RESIZE_DIAGONAL_TOP_LEFT      = 5;
  private final int RESIZE_DIAGONAL_BOTTOM_LEFT   = 6;
  private final int RESIZE_DIAGONAL_TOP_RIGHT     = 7;
  private final int RESIZE_DIAGONAL_BOTTOM_RIGHT  = 8;
  
  public static final int JOINT_LEFT   = 1;
  public static final int JOINT_RIGHT  = 2;
  public static final int JOINT_TOP    = 3;
  public static final int JOINT_BOTTOM = 4;
    
  private Vector<MapComponent> items = new Vector<MapComponent>();
  private Vector<Integer> copyIndex = new Vector<Integer>();
  private transient Vector<ComponentEvent> events = null;// new Vector<ComponentEvent>();
  private ArrayList<Integer> selectedItems = new ArrayList<Integer>();
  private boolean mouseDown = false;
  private int mouseResize = 0;
  private MapComponent resizeComponent;
  private int floatingComponentIndex = -1;
  private Point startPos,endPos;
  private Hashtable<Integer,Point> mousePos = new Hashtable<Integer, Point>();
  private double meterPerPixel = 0.04;
  private int floorNum = 0;
  
  public WorkArea(int flNum) {
            setBackground(Color.white);
            setFocusable(true);
            floorNum = flNum;
        }
  
  /**
   * method, which set listener for mouse, useful when object is deserialized
   */
  public void setListeners(){
      addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            @Override
                public void mouseDragged(MouseEvent e) {
                    areaMouseDragged(e);
                }
            @Override
                public void mouseMoved(MouseEvent e){
                    areaMouseMoved(e);
                }
            });
            addMouseListener(new java.awt.event.MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent evt) {
                areaMouseClicked(evt);
            }
            @Override
            public void mousePressed(MouseEvent evt){
                areaMousePressed(evt);
            }
            @Override
            public void mouseReleased(MouseEvent evt){
                areaMouseReleased(evt);
            }
            });
  }
  
  /**
   * return floor number
   * @return floor number
   */
  public int getFloorNumber(){
      return floorNum;
  }
  
  /**
   * return road list for graph
   * @return road list
   */
  public Vector<RoadData> getRoadlist(){
      Vector<Road> roads = new Vector<Road>();
      Vector<RoadData> ret = new Vector<RoadData>();
      Vector<Exit> exits = new Vector<Exit>();
      //naredimo seznam cest in izhodov
      for(int i=0;i<items.size();i++){
          if(items.get(i) instanceof Road)
              roads.add((Road) items.get(i));
          if(items.get(i) instanceof Exit)
              exits.add((Exit) items.get(i));
      }
      //dokler ne obdelamo vseh cest
      while(roads.size()>0){
          //vsaki cesti določimo dolžino
          Road comp = roads.get(0);
          roads.remove(0);
          RoadData data = new RoadData();
          Rectangle interSide;
          Road nRoad = comp;
          Road retRoad;
          //določimo število parkirnih mest
          data.numParkLot = 0;
          //določimo kje so sosedna mesta
          Rectangle left = new Rectangle(1,comp.getHeight());
          left.setLocation(comp.getX()-1, comp.getY());
          Rectangle right = new Rectangle(1,comp.getHeight());
          right.setLocation(comp.getX()+comp.getWidth(), comp.getY());
          Rectangle top = new Rectangle(comp.getWidth(), 1);
          top.setLocation(comp.getX(), comp.getY()-1);
          Rectangle bottom = new Rectangle(comp.getWidth(), 1);
          bottom.setLocation(comp.getX(), comp.getY()+comp.getHeight());
          String orient = (String) comp.getPropertyValue("Orientation");
          //glede na to ali je cesta horizontalna ali vertikalna
          if(orient.equals("Horizontal")){
            //določimo dolžino ceste
            data.length = comp.getWidthMeters();
            //dodamo vse ceste, ki so sosednje na levi strani
            do{
                interSide = new Rectangle(1,nRoad.getHeight());
                interSide.setLocation(nRoad.getX()+nRoad.getWidth(), nRoad.getY());
                retRoad = null;
                for(int i=0;i<items.size();i++){
                    MapComponent temp = items.get(i);
                    if(temp instanceof Road && nRoad!=temp && temp.jointSide(JOINT_RIGHT)
                       && temp.getBounds().intersects(interSide)){
                        retRoad = (Road) items.get(i);
                    }
                }
                nRoad = retRoad;
                if(nRoad!=null){
                    data.length += nRoad.getWidthMeters();
                    top.width += nRoad.getWidth();
                    bottom.width += nRoad.getWidth();
                    right.x += nRoad.getWidth();
                    roads.remove(nRoad);
                }
            }while(nRoad != null);
            nRoad = comp;
            //dodamo vse ceste, ki so sosednje na desni strani
            do{
                interSide = new Rectangle(1,nRoad.getHeight());
                interSide.setLocation(nRoad.getX()-1, nRoad.getY());
                retRoad = null;
                for(int i=0;i<items.size();i++){
                    MapComponent temp = items.get(i);
                    if(temp instanceof Road && nRoad!=temp && temp.jointSide(JOINT_LEFT)
                       && temp.getBounds().intersects(interSide)){
                        retRoad = (Road) items.get(i);
                    }
                }
                nRoad = retRoad;
                if(nRoad!=null){
                    data.length += nRoad.getWidthMeters();
                    top.width += nRoad.getWidth();
                    top.x -= nRoad.getWidth();
                    bottom.width += nRoad.getWidth();
                    bottom.x -= nRoad.getWidth();
                    left.x -= nRoad.getWidth();
                    roads.remove(nRoad);
                }
            }while(nRoad != null);
            //preštejemo parkirna mesta
            for(int i=0;i<items.size();i++)
                if(items.get(i) instanceof ParkingBox){
                    Rectangle temp = items.get(i).getBounds();
                    if((temp.intersects(top) || temp.intersects(bottom))&& 
                       items.get(i).getPropertyValue("Orientation").equals("Vertical"))
                        data.numParkLot++;
                }
          } else {
            //isto naredimo še za vertikalne ceste
            data.length = comp.getHeightMeters();
            do{
                interSide = new Rectangle(nRoad.getWidth(), 1);
                interSide.setLocation(nRoad.getX(), nRoad.getY()+nRoad.getHeight());
                retRoad = null;
                for(int i=0;i<items.size();i++){
                    MapComponent temp = items.get(i);
                    if(temp instanceof Road && nRoad!=temp && temp.jointSide(JOINT_BOTTOM)
                       && temp.getBounds().intersects(interSide)){
                        retRoad = (Road) items.get(i);
                    }
                }
                nRoad = retRoad;
                if(nRoad!=null){
                    data.length += nRoad.getHeightMeters();
                    left.height += nRoad.getHeight();
                    right.height += nRoad.getHeight();
                    bottom.y += nRoad.getHeight();
                    roads.remove(nRoad);
                }
            }while(nRoad != null);
            nRoad = comp;
            do{
                interSide = new Rectangle(nRoad.getWidth(), 1);
                interSide.setLocation(nRoad.getX(), nRoad.getY()-1);
                retRoad = null;
                for(int i=0;i<items.size();i++){
                    MapComponent temp = items.get(i);
                    if(temp instanceof Road && comp!=temp && temp.jointSide(JOINT_TOP)
                       && temp.getBounds().intersects(interSide)){
                        retRoad = (Road) items.get(i);
                    }
                }
                nRoad = retRoad;
                if(nRoad!=null){
                    data.length += nRoad.getHeightMeters();
                    left.height += nRoad.getHeight();
                    left.x -= nRoad.getHeight();
                    right.height += nRoad.getHeight();
                    right.x -= nRoad.getHeight();
                    top.y -= nRoad.getHeight();
                    roads.remove(nRoad);
                }
            }while(nRoad != null);
            for(int i=0;i<items.size();i++)
                if(items.get(i) instanceof ParkingBox){
                    Rectangle temp = items.get(i).getBounds();
                    if(temp.intersects(left) || temp.intersects(right)){
                       if(items.get(i).getPropertyValue("Orientation").equals("Horizontal"))
                        data.numParkLot++;
                       if(items.get(i).getPropertyValue("Orientation").equals("Diagonal"))
                        data.numParkLot += 2;
                    }
                }
          }
          for(int i=0;i<items.size();i++){
              Rectangle bounds = items.get(i).getBounds();
                if(items.get(i) instanceof CrossRoad || items.get(i) instanceof Turn){
                    if(orient.equals("Horizontal")){
                        if(bounds.intersects(left) && items.get(i).jointSide(JOINT_RIGHT))
                            data.start = items.get(i);
                        if(bounds.intersects(right) && items.get(i).jointSide(JOINT_LEFT))
                            data.end = items.get(i);
                    } else {
                        if(bounds.intersects(top) && items.get(i).jointSide(JOINT_BOTTOM))
                            data.start = items.get(i);
                        if(bounds.intersects(bottom)  && items.get(i).jointSide(JOINT_TOP))
                            data.end = items.get(i);
                    }
                }
          }
          //izračunamo še oddaljenost od najbližjega izhoda
          Point roadCenter = new Point(top.x+(top.width/2),right.y+(right.height/2));
          for(int i=0;i<exits.size();i++){
              Rectangle temp = exits.get(i).getBounds();
              Point exitCenter = new Point(temp.x+(temp.width/2),temp.y+(temp.height/2));
              if(data.distanceExit==0 || data.distanceExit > roadCenter.distance(exitCenter)){
                  data.distanceExit = roadCenter.distance(exitCenter);              
                  data.exitName = exits.get(i).getName();
              }
          }
          data.distanceExit *= meterPerPixel;
          ret.add(data);
      }
      return ret;
  }
 
  /**
   * add component listener
   * @param event component listener
   */
  public void addComponentListener(ComponentEvent event){
      if(events==null)
          events = new Vector<ComponentEvent>();
      events.add(event);
  }
  
  /**
   * remove component listener
   * @param event component listener
   */
  public void removeComponentListener(ComponentEvent event){
      if(events!=null)
        events.remove(event);
  }
  
  /**
   * copy selected components
   */
  public void copySelectedComponents(){
      copyIndex.clear();
      copyIndex.addAll(selectedItems);
  }
  
  /**
   * paste copied components
   */
  public void pasteCopiedComponents(){
      Vector<Integer> newSelected = new Vector<Integer>();
      //vsak element, ki je kopiran, podvojimo in zamaknemo za 10 pikslov
      for(int i=0;i<copyIndex.size();i++){
          MapComponent temp = items.get(copyIndex.get(i)).duplicate();
          Point newPos = temp.getLocation();
          newPos.translate(-10, -10);
          temp.setLocation(newPos);
          checkName(temp);
          items.add(temp);
          newSelected.add(items.indexOf(temp));
          for(int j=0;j<events.size();j++){
              events.get(j).componentAdded(temp);
          }
      }
      selectedItems.clear();
      selectedItems.addAll(newSelected);
      repaint();
  }
  
  /**
   * remove selected components
   */
  public void removeSelectedComponent(){
     Vector<MapComponent> removeList = new Vector<MapComponent>();
     for(int i=0;i<selectedItems.size();i++){
         for(int j=0;j<events.size();j++)
             events.get(j).componentRemoved(items.get(selectedItems.get(i)));
         removeList.add(items.get(selectedItems.get(i)));
     }
     items.removeAll(removeList);
     copyIndex.removeAll(selectedItems);
     selectedItems.clear();
     repaint(); 
  }
  
  /**
   * returns list of all components
   * @return list of all components
   */
  public Vector<MapComponent> getAllComponents(){
      return new Vector<MapComponent>(items);
  }
  
  /**
   * add component to floor
   * @param component new component to add
   */
  public void addMapComponent(MapComponent component){
      //preverimo, če izbrana komponenta že obstaja
      if(items.contains(component)) return;
      component.setSize((int)(component.getWidthMeters()/meterPerPixel),
                        (int)(component.getHeightMeters()/meterPerPixel));
      component.setMetersPerPixel(meterPerPixel);
      checkName(component);
      items.add(component);
      for(int i=0;i<events.size();i++){
          events.get(i).componentAdded(component);
      }
      repaint();
  }
  
  /**
   * check if name allready exist. If exist, make name unique
   * @param component component, for which we check name
   */
  private void checkName(MapComponent component){
      boolean nameUnique = true;
      //preverimo če je ime edinstveno
      for(int i=0;i<items.size();i++)
          if(items.get(i).getName().equals(component.getName())){
              nameUnique = false;
              break;
          }
      //če že obstaja, dodamo številke, tako da bo edinstveno
      if(!nameUnique){
          String newName = "";
          int index = 1;
          while(!nameUnique){
              newName = component.getName() + Integer.toString(index);
              nameUnique = true;
              for(int i=0;i<items.size();i++)
                  if(items.get(i).getName().equals(newName)){
                      nameUnique = false;
                      break;
                  }
              index++;
          }
          component.setName(newName);
      }
  }
  
  /**
   * add componet such way, that we can choose location with a mouse
   * @param component
   */
  public void addMapComponentFloating(MapComponent component){
      if(floatingComponentIndex>-1)
          items.remove(floatingComponentIndex);
      component.setSize((int)(component.getWidthMeters()/meterPerPixel),
                        (int)(component.getHeightMeters()/meterPerPixel));
      component.setMetersPerPixel(meterPerPixel);
      checkName(component);
      items.add(component);
      floatingComponentIndex = items.indexOf(component);
  }
  
  /**
   * check if is mouse in resize area
   * @param p point to check
   * @return which side we can resize
   */
  private int isResizeArea(Point p){
      //to lahko naredimo samo za 1 izbrano komponento
      if(selectedItems.size()==1){
          //preverimo za diagonalno spreminjanje velikosti
          if(items.get(selectedItems.get(0)).isDiagonalResizable()){
              Rectangle obmocje = new  Rectangle(items.get(selectedItems.get(0)).getBounds());
              obmocje.setSize(4,4);
              if(obmocje.contains(p))
                  return RESIZE_DIAGONAL_TOP_LEFT;
              obmocje.setBounds(items.get(selectedItems.get(0)).getBounds());
              obmocje.x = obmocje.x+obmocje.width-4;
              obmocje.setSize(4,4);
              if(obmocje.contains(p))
                  return RESIZE_DIAGONAL_TOP_RIGHT;
              obmocje.setBounds(items.get(selectedItems.get(0)).getBounds());
              obmocje.y = obmocje.y+obmocje.height-4;
              obmocje.setSize(4,4);
              if(obmocje.contains(p))
                  return RESIZE_DIAGONAL_BOTTOM_LEFT;
              obmocje.setBounds(items.get(selectedItems.get(0)).getBounds());
              obmocje.y = obmocje.y+obmocje.height-4;
              obmocje.x = obmocje.x+obmocje.width-4;
              obmocje.setSize(4,4);
              if(obmocje.contains(p))
                  return RESIZE_DIAGONAL_BOTTOM_RIGHT;
          }
          //preverimo za vertikalno spreminjanje velikosti
          if(items.get(selectedItems.get(0)).isVerticalResizable()){
                  Rectangle obmocje = new  Rectangle(items.get(selectedItems.get(0)).getBounds());
                  obmocje.y = obmocje.y+obmocje.height-4;
                  obmocje.height = 4;
                  if(obmocje.contains(p))
                      return RESIZE_VERTICAL_BOTTOM;
                  obmocje.setBounds(items.get(selectedItems.get(0)).getBounds());
                  obmocje.height = 4;
                  if(obmocje.contains(p))
                      return RESIZE_VERTICAL_TOP;
              }
          //preverimo za horizontalno spreminjanje velikosti
          if(items.get(selectedItems.get(0)).isHorizontalResizable()){
                  Rectangle obmocje = new  Rectangle(items.get(selectedItems.get(0)).getBounds());
                  obmocje.x = obmocje.x+obmocje.width-4;
                  obmocje.width = 4;
                  if(obmocje.contains(p))
                     return RESIZE_HORIZONTAL_RIGHT;
                  obmocje.setBounds(items.get(selectedItems.get(0)).getBounds());
                  obmocje.width = 4;
                  if(obmocje.contains(p))
                     return RESIZE_HORIZONTAL_LEFT;
              }
      }
      return 0;
  }
  
  /**
   * check if component location intersects with another component
   * @param comp component which we checking
   * @return true, if is valid location otherwise false
   */
  private boolean checkValidBounds(MapComponent comp){
      for(int i=0;i<items.size();i++)
          if(items.get(i)!=comp && items.get(i).getBounds().intersects(comp.getBounds()))
              return false;
      return true;
  }
  
  /**
   * set floor number
   * @param num new floor number
   */
  public void setFloorNumber(int num){
      floorNum = num;
  }

/**
 * check proximitiy with another component and if it is close enough, change component location
 * @param comp component which location we are checking
 */
private void checkProximity(MapComponent comp){
             Rectangle interRect = new Rectangle(0,0,-1,-1);
             boolean changed = false;
             //preverimo z vsako komponento
             for(int i=0;i<items.size();i++)
                 if(items.get(i)!=comp){
                     //preverimo desno stran
                     Rectangle jointComp = items.get(i).getBounds();
                     interRect.setLocation(comp.getX()+comp.getWidth(),comp.getY());
                     interRect.setSize(10,comp.getHeight());
                     if(interRect.intersects(jointComp)){
                         comp.setLocation(jointComp.x-comp.getWidth(), interRect.y);
                         if(jointComp.height>=(int)(comp.minHeightMeters()/meterPerPixel)
                            && comp.jointSide(JOINT_RIGHT) && items.get(i).jointSide(JOINT_LEFT)){
                             comp.setHeightMeters(items.get(i).getHeightMeters());
                             comp.setSize(comp.getWidth(),jointComp.height);
                             comp.setLocation(comp.getX(),jointComp.y);
                             changed = true;
                         }
                      }   
                      //preverimo levo stran
                      interRect.x = comp.getX()-10;
                      if(jointComp.intersects(interRect)){
                          comp.setLocation(jointComp.x+jointComp.width, comp.getY());
                          if(jointComp.height>=(int)(comp.minHeightMeters()/meterPerPixel)
                            && comp.jointSide(JOINT_LEFT) && items.get(i).jointSide(JOINT_RIGHT)){
                             comp.setHeightMeters(items.get(i).getHeightMeters());
                             comp.setSize(comp.getWidth(),jointComp.height);
                             comp.setLocation(comp.getX(),jointComp.y);
                             changed = true;
                         }
                      }
                      //preverimo zgornjo stran
                      interRect.setLocation(comp.getX(),comp.getY()-10);
                      interRect.setSize(comp.getWidth(),10);
                      if(jointComp.intersects(interRect)){
                         comp.setLocation(comp.getX(),jointComp.y+jointComp.height);
                         if(jointComp.width>=(int)(comp.minWidthMeters()/meterPerPixel)
                            && comp.jointSide(JOINT_TOP) && items.get(i).jointSide(JOINT_BOTTOM)){
                             comp.setWidthMeters(items.get(i).getWidthMeters());
                             comp.setSize(jointComp.width,comp.getHeight());
                             comp.setLocation(jointComp.x,comp.getY());
                             changed = true;
                         }
                      }
                      //preverimo spodnjo stran
                      interRect.y = comp.getY()+comp.getHeight();
                      if(jointComp.intersects(interRect)){
                         comp.setLocation(comp.getX(),jointComp.y-comp.getHeight());
                         if(jointComp.width>=(int)(comp.minWidthMeters()/meterPerPixel)
                            && comp.jointSide(JOINT_BOTTOM) && items.get(i).jointSide(JOINT_TOP)){
                             comp.setWidthMeters(items.get(i).getWidthMeters());
                             comp.setSize(jointComp.width,comp.getHeight());
                             comp.setLocation(jointComp.x,comp.getY());
                             changed = true;
                         }
                      }
                 }
                 //če je spremenjena kakšna lastnost, spročimo dogodek
                  if(changed)
                      for(int j=0;j<events.size();j++)
                        events.get(j).propertyChanged(comp);
  }
 
/**
 * mouse handler
 * @param evt
 */
  private void areaMouseMoved(MouseEvent evt){
      //popravimo lokacijo za "plavajočo" komponento
      if(floatingComponentIndex>-1){
          MapComponent temp = items.get(floatingComponentIndex);
          temp.setLocation(evt.getX()-temp.getWidth()/2, evt.getY()-temp.getHeight()/2);
          repaint();
          return;
      }
      //če je možno spremeniti velikost komponenti, izrišemo ustrezni kurzor
      if(selectedItems.size()==1){
          Cursor newCursor;
          switch(isResizeArea(evt.getPoint())){
             case RESIZE_HORIZONTAL_RIGHT:
                 newCursor = new Cursor(Cursor.E_RESIZE_CURSOR);
             break;
             case RESIZE_VERTICAL_BOTTOM:
                 newCursor = new Cursor(Cursor.S_RESIZE_CURSOR);
             break;
             case RESIZE_VERTICAL_TOP:
                 newCursor = new Cursor(Cursor.N_RESIZE_CURSOR);
             break;
             case RESIZE_HORIZONTAL_LEFT:
                 newCursor = new Cursor(Cursor.W_RESIZE_CURSOR);
             break;
             case RESIZE_DIAGONAL_TOP_LEFT:
                 newCursor = new Cursor(Cursor.NW_RESIZE_CURSOR);
             break;
             case RESIZE_DIAGONAL_TOP_RIGHT:
                 newCursor = new Cursor(Cursor.NE_RESIZE_CURSOR);
             break;
             case RESIZE_DIAGONAL_BOTTOM_LEFT:
                 newCursor = new Cursor(Cursor.SW_RESIZE_CURSOR);
             break;
             case RESIZE_DIAGONAL_BOTTOM_RIGHT:
                 newCursor = new Cursor(Cursor.SE_RESIZE_CURSOR);
             break;
             default:
                 newCursor = new Cursor(Cursor.DEFAULT_CURSOR);
             break;
          }
          setCursor(newCursor);
      }
  }
  
  /**
   * mouse handler for dragging
   * @param evt
   */
  private void areaMouseDragged(MouseEvent evt){
     if(mouseDown){
         //preverimo, če smo mislili s pritiskom miške premakniti 1 komponento ali več
         if(selectedItems.size()==1){
             int selected = selectedItems.get(0);
             Rectangle bounds = items.get(selected).getBounds();
             double mWidth = items.get(selected).getWidthMeters();
             double mHeight = items.get(selected).getHeightMeters();
             items.get(selected).setLocation(evt.getX()-mousePos.get(selected).x,
                                             evt.getY()-mousePos.get(selected).y);
             if(!checkValidBounds(items.get(selected))){
                 items.get(selected).setHeightMeters(mHeight);
                 items.get(selected).setWidthMeters(mWidth);
                 items.get(selected).setBounds(bounds);
             }
             checkProximity(items.get(selectedItems.get(0)));
         } else {
             for(int i=0;i<selectedItems.size();i++){
                 int selected = selectedItems.get(i);
                 items.get(selected).setLocation(evt.getX()-mousePos.get(selected).x,
                                                       evt.getY()-mousePos.get(selected).y);
             }    
         }
     } else {
         //končna točka za selekcijo
         endPos = evt.getPoint();
     }
     if(mouseResize!=0){
         //če smo hoteli spremeniti velikost, popravimo velikost komponente
         int velikost;
         Point  corner;
         Rectangle temp;
         Rectangle compBounds = resizeComponent.getBounds();
         boolean resize = true;
         switch(mouseResize){
             case RESIZE_HORIZONTAL_RIGHT:
                 compBounds.width = evt.getX()-compBounds.x;
                 if(compBounds.width*meterPerPixel < resizeComponent.minWidthMeters())
                     resize = false;
             break;
             case RESIZE_VERTICAL_BOTTOM:
                 compBounds.height = evt.getY()-compBounds.y;
                 if(compBounds.height*meterPerPixel < resizeComponent.minHeightMeters())
                     resize = false;
             break;
             case RESIZE_VERTICAL_TOP:
                 int globina = compBounds.y+compBounds.height;
                 compBounds.y = evt.getY();
                 compBounds.height = globina-evt.getY();
                 if(compBounds.height*meterPerPixel < resizeComponent.minHeightMeters())
                     resize = false;
             break;
             case RESIZE_HORIZONTAL_LEFT:
                 int dolzina = compBounds.x+compBounds.width;
                 compBounds.x = evt.getX();
                 compBounds.width = dolzina-evt.getX();
                 if(compBounds.width*meterPerPixel < resizeComponent.minWidthMeters())
                     resize = false;
             break;
             case RESIZE_DIAGONAL_TOP_LEFT:
                 corner = new Point(compBounds.x+compBounds.width,compBounds.y+compBounds.height);
                 temp = new Rectangle(corner);
                 velikost = corner.y - evt.getY();
                 temp.add(corner.x-velikost,evt.getY());
                 compBounds.setBounds(temp);
                 if(compBounds.width*meterPerPixel < resizeComponent.minWidthMeters())
                     resize = false;
             break;
             case RESIZE_DIAGONAL_TOP_RIGHT:
                 corner = new Point(compBounds.x,compBounds.y+compBounds.height);
                 temp = new Rectangle(corner);
                 velikost = corner.y - evt.getY();
                 temp.add(corner.x+velikost,evt.getY());
                 compBounds.setBounds(temp);
                 if(compBounds.width*meterPerPixel < resizeComponent.minWidthMeters())
                     resize = false;
             break;
             case RESIZE_DIAGONAL_BOTTOM_LEFT:
                 corner = new Point(compBounds.x+compBounds.width,compBounds.y);
                 temp = new Rectangle(corner);
                 velikost = corner.y - evt.getY();
                 temp.add(corner.x+velikost,evt.getY());
                 compBounds.setBounds(temp);
                 if(compBounds.width*meterPerPixel < resizeComponent.minWidthMeters())
                     resize = false;
             break;
             case RESIZE_DIAGONAL_BOTTOM_RIGHT:
                 velikost = evt.getX();
                 if(evt.getY()>velikost)
                     velikost = evt.getY();
                 velikost -= compBounds.x;
                 compBounds.setSize(velikost, velikost);
                 if(compBounds.width*meterPerPixel < resizeComponent.minWidthMeters())
                     resize = false;
             break;
         }
         if(resize){
            resizeComponent.setBounds(compBounds);
            resizeComponent.setWidthMeters(meterPerPixel*compBounds.width);
            resizeComponent.setHeightMeters(meterPerPixel*compBounds.height);
         }
     }
     repaint();
  }
  
  /**
   * mouse handler for mouse move
   * @param evt
   */
  private void areaMousePressed(MouseEvent evt) {
    if(floatingComponentIndex>-1)
        return;
    if(evt.getButton()==MouseEvent.BUTTON1){
        //preverimo kaj smo z pritiskom mislili
        int temp = pointOnComponent(evt.getPoint());
        if(temp>-1){
            if(isResizeArea(evt.getPoint())==0){
                mouseDown = true;
                if(!evt.isShiftDown() && !selectedItems.contains(temp))
                    selectedItems.clear();
                if(!selectedItems.contains(temp)){
                    selectedItems.add(temp);
                    sendSelectedEvent();
                }
                mousePos.clear();
                for(int i=0;i<selectedItems.size();i++){
                    int zacasno = selectedItems.get(i);
                    int dx = evt.getX() - items.get(zacasno).getLocation().x;
                    int dy = evt.getY() - items.get(zacasno).getLocation().y;
                    mousePos.put(zacasno,new Point(dx,dy));
                }
            } else {
                mouseResize = isResizeArea(evt.getPoint());
                resizeComponent = items.get(pointOnComponent(evt.getPoint()));
            }
        } else {
               selectedItems.clear();
               startPos = evt.getPoint();
        }
    }
    repaint();
  }
  
  /**
   * send event, when components are selected
   */
  private void sendSelectedEvent(){
      Vector<MapComponent> temp = new Vector<MapComponent>();
      for(int i=0;i<selectedItems.size();i++)
          temp.add(items.get(selectedItems.get(i)));
      for(int i=0;i<events.size();i++)
          events.get(i).componentSelected(temp);
  }
  
  /**
   * clear selection
   */
  public void clearSelection(){
      selectedItems.clear();
      repaint();
  }
  
  /**
   * mouse handler, when mouse button is released
   * @param evt
   */
  private void areaMouseReleased(MouseEvent evt){
      if(mouseResize!=0)
          for(int i=0;i<events.size();i++)
              events.get(i).propertyChanged(resizeComponent);
      mouseDown = false;
      if(startPos!=null && endPos!=null){
           Rectangle dimenzija = new Rectangle(startPos);
           dimenzija.add(endPos);
           for(int i=0;i<items.size();i++)
               if(dimenzija.contains(items.get(i).getBounds()))
                   selectedItems.add(i);
           if(selectedItems.size()>0)
               sendSelectedEvent();
      }
      startPos = null;
      endPos = null;
      mouseResize=0;
      repaint();
  }
  
  /**
   * check which component, if any, is under point p
   * @param p point to check
   * @return index of component on point p, else -1
   */
  private int pointOnComponent(Point p){
      int i = 0;
      //za vsako komponento
      while(i<items.size()){
          //preverimo če vsebuje točko
          if(items.elementAt(i).getBounds().contains(p))
              return i;     //če jo, vrnemo index iskane komponente
          i++;
      }   
      return -1;
  }
  
  /**
   * change ratio between meters and pixel
   * @param mpp new ratio
   */
  public void setMetersPerPixel(double mpp){
      for(int i=0;i<items.size();i++){
        items.get(i).setSize((int)(items.get(i).getWidthMeters()/mpp),
                             (int)(items.get(i).getHeightMeters()/mpp));
        items.get(i).setLocation((int)(items.get(i).getLocation().x*meterPerPixel/mpp),
                                 (int)(items.get(i).getLocation().y*meterPerPixel/mpp));
        items.get(i).setMetersPerPixel(mpp);
      }
      meterPerPixel = mpp;
      repaint();
  }
  
  /**
   * get ratio between meters and pixel
   * @return ratio
   */
  public double getMetersPerPixel(){
      return meterPerPixel;
  }
  
  /**
   * mouse handler when mouse button is clicked
   * @param evt
   */
  private void areaMouseClicked(java.awt.event.MouseEvent evt) {
      if(evt.getButton()==MouseEvent.BUTTON1){
           //če dodajamo komponento, jo fiksiramo
           if(floatingComponentIndex>-1){
               if(!checkValidBounds(items.get(floatingComponentIndex)))
                   return;
               checkProximity(items.get(floatingComponentIndex));
               selectedItems.clear();
               selectedItems.add(floatingComponentIndex);
               for(int i=0;i<events.size();i++){
                   events.get(i).componentAdded(items.get(floatingComponentIndex));
               }
               sendSelectedEvent();
               floatingComponentIndex = -1;
               return;
           }
           //drugače damo komponento med izbrane
           int selected = pointOnComponent(new Point(evt.getX(),evt.getY()));
           if(selected>-1){
               if(!evt.isShiftDown())
                    selectedItems.clear();
               selectedItems.add(selected);
               sendSelectedEvent();
           } else
               selectedItems.clear();
      } else if(evt.getButton()==MouseEvent.BUTTON3){
            //če hočemo dodat komponento, jo odstranimo
            if(floatingComponentIndex>-1){
                items.remove(floatingComponentIndex);
                floatingComponentIndex = -1;
                return;
            }
            //drugače prikažemo meni
            int temp = pointOnComponent(evt.getPoint());
            if(temp>-1){
                    if(!selectedItems.contains(temp)){
                        selectedItems.clear();
                        selectedItems.add(temp);
                        sendSelectedEvent();
                    }
            } else
                   selectedItems.clear();
            JPopupMenu popup = new JPopupMenu();
            JMenuItem mItem;
            if(selectedItems.size()>0){
                mItem = new JMenuItem("Copy");
                mItem.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent arg0) {
                        copySelectedComponents();
                    }
                });
                popup.add(mItem);
                mItem = new JMenuItem("Delete");
                mItem.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent arg0) {
                        removeSelectedComponent();
                    }
                });
                popup.add(mItem);
            }
            if(copyIndex.size()>0){
                mItem = new JMenuItem("Paste");
                mItem.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent arg0) {
                        pasteCopiedComponents();
                    }
                });
                popup.add(mItem);
            }
            if(popup.getComponentCount()>0)
                popup.show(this, evt.getX(), evt.getY());
      }
       repaint();
    }
  
  /**
   * paint all components
   * @param g
   */
  @Override
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D)g;
    Dimension viewDimension = new Dimension(0, 0);
    //paint all components
    for(int i=0;i<items.size();i++){
        items.get(i).paint(g2d);
        if(items.get(i).getX()+items.get(i).getWidth()>viewDimension.width)
            viewDimension.width = items.get(i).getX()+items.get(i).getWidth()+100;
        if(items.get(i).getY()+items.get(i).getHeight()>viewDimension.height)
            viewDimension.height = items.get(i).getY()+items.get(i).getHeight()+100;
        //če je komponenta izbrana, jo obrobimo
        if(selectedItems.contains(i)){
           g2d.setColor(Color.BLUE); 
           g2d.setStroke(new BasicStroke(2)); 
           g2d.drawRect(items.elementAt(i).getLocation().x, items.elementAt(i).getLocation().y,
                        items.elementAt(i).getWidth(), items.elementAt(i).getHeight()); 
           g2d.setColor(Color.BLACK); 
           g2d.setStroke(new BasicStroke(1)); 
        }
    }
    //popravimo velikost za scrollbare
    if(viewDimension.width>getPreferredSize().width || viewDimension.height>getPreferredSize().height){
        setPreferredSize(viewDimension);
        revalidate();
    }
    //če spreminjamo velikost, izpišemo še informativno velikost
    if(mouseResize>0){
        FontMetrics fm = getFontMetrics(g2d.getFont());
        int fontWidth;
        String izpis;
        int fontHeight = g2d.getFont().getSize();
        
        switch(mouseResize){
                 case RESIZE_HORIZONTAL_RIGHT:
                 case RESIZE_HORIZONTAL_LEFT:
                 case RESIZE_DIAGONAL_BOTTOM_RIGHT:
                 case RESIZE_DIAGONAL_BOTTOM_LEFT:
                     izpis = String.format("%.2f m", resizeComponent.getWidthMeters());
                     fontWidth = fm.stringWidth(izpis);
                     g2d.drawRect(resizeComponent.getX()+resizeComponent.getWidth()/2-fontWidth/2-2,
                                  resizeComponent.getY()-fontHeight-7, fontWidth+4, fontHeight+4);
                     g2d.setColor(Color.YELLOW);
                     g2d.fillRect(resizeComponent.getX()+resizeComponent.getWidth()/2-fontWidth/2-1,
                                  resizeComponent.getY()-fontHeight-6, fontWidth+3, fontHeight+3);
                     g2d.setColor(Color.BLACK);
                     g2d.drawString(izpis,resizeComponent.getX()+resizeComponent.getWidth()/2-fontWidth/2,
                                    resizeComponent.getY()-fontHeight+6);
                 break;
                 case RESIZE_VERTICAL_BOTTOM:
                 case RESIZE_VERTICAL_TOP:
                 case RESIZE_DIAGONAL_TOP_LEFT:
                 case RESIZE_DIAGONAL_TOP_RIGHT:    
                     izpis = String.format("%.2f m", resizeComponent.getHeightMeters());
                     fontWidth = fm.stringWidth(izpis);
                     g2d.drawRect(resizeComponent.getX()+resizeComponent.getWidth()+3, 
                                  resizeComponent.getY()+resizeComponent.getHeight()/2-fontHeight/2-2,
                                  fontWidth+4, fontHeight+4);
                     g2d.setColor(Color.YELLOW);
                     g2d.fillRect(resizeComponent.getX()+resizeComponent.getWidth()+4, 
                                  resizeComponent.getY()+resizeComponent.getHeight()/2-fontHeight/2-1,
                                  fontWidth+3, fontHeight+3);
                     g2d.setColor(Color.BLACK);
                     g2d.drawString(izpis, resizeComponent.getX()+resizeComponent.getWidth()+5,
                                    resizeComponent.getY()+resizeComponent.getHeight()/2+fontHeight/2);
                 break;
              }
    }
    if(startPos!=null && endPos!=null){
        Rectangle dimenzija = new Rectangle(startPos);
        dimenzija.add(endPos);
        g2d.drawRect(dimenzija.x,dimenzija.y,dimenzija.width,dimenzija.height);
    }
  }
}
